/**
 * jQuery JSON Plugin
 * version: 2.1 (2009-08-14)
 *
 * This document is licensed as free software under the terms of the
 * MIT License: http://www.opensource.org/licenses/mit-license.php
 *
 * Brantley Harris wrote this plugin. It is based somewhat on the JSON.org 
 * website's http://www.json.org/json2.js, which proclaims:
 * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
 * I uphold.
 *
 * It is also influenced heavily by MochiKit's serializeJSON, which is 
 * copyrighted 2005 by Bob Ippolito.
 */
 
(function($) {
	/** jQuery.toJSON( json-serializble )
		Converts the given argument into a JSON respresentation.

		If an object has a "toJSON" function, that will be used to get the representation.
		Non-integer/string keys are skipped in the object, as are keys that point to a function.

		json-serializble:
			The *thing* to be converted.
	 **/
	$.toJSON = function(o)
	{
		if (typeof(JSON) == 'object' && JSON.stringify)
			return JSON.stringify(o);
		
		var type = typeof(o);
	
		if (o === null)
			return "null";
	
		if (type == "undefined")
			return undefined;
		
		if (type == "number" || type == "boolean")
			return o + "";
	
		if (type == "string")
			return $.quoteString(o);
	
		if (type == 'object')
		{
			if (typeof o.toJSON == "function") 
				return $.toJSON( o.toJSON() );
			
			if (o.constructor === Date)
			{
				var month = o.getUTCMonth() + 1;
				if (month < 10) month = '0' + month;

				var day = o.getUTCDate();
				if (day < 10) day = '0' + day;

				var year = o.getUTCFullYear();
				
				var hours = o.getUTCHours();
				if (hours < 10) hours = '0' + hours;
				
				var minutes = o.getUTCMinutes();
				if (minutes < 10) minutes = '0' + minutes;
				
				var seconds = o.getUTCSeconds();
				if (seconds < 10) seconds = '0' + seconds;
				
				var milli = o.getUTCMilliseconds();
				if (milli < 100) milli = '0' + milli;
				if (milli < 10) milli = '0' + milli;

				return '"' + year + '-' + month + '-' + day + 'T' +
							 hours + ':' + minutes + ':' + seconds + 
							 '.' + milli + 'Z"'; 
			}

			if (o.constructor === Array) 
			{
				var ret = [];
				for (var i = 0; i < o.length; i++)
					ret.push( $.toJSON(o[i]) || "null" );

				return "[" + ret.join(",") + "]";
			}
		
			var pairs = [];
			for (var k in o) {
				var name;
				var type = typeof k;

				if (type == "number")
					name = '"' + k + '"';
				else if (type == "string")
					name = $.quoteString(k);
				else
					continue;  //skip non-string or number keys
			
				if (typeof o[k] == "function") 
					continue;  //skip pairs where the value is a function.
			
				var val = $.toJSON(o[k]);
			
				pairs.push(name + ":" + val);
			}

			return "{" + pairs.join(", ") + "}";
		}
	};

	/** jQuery.evalJSON(src)
		Evaluates a given piece of json source.
	 **/
	$.evalJSON = function(src)
	{
		if (typeof(JSON) == 'object' && JSON.parse)
			return JSON.parse(src);
		return eval("(" + src + ")");
	};
	
	/** jQuery.secureEvalJSON(src)
		Evals JSON in a way that is *more* secure.
	**/
	$.secureEvalJSON = function(src)
	{
		if (typeof(JSON) == 'object' && JSON.parse)
			return JSON.parse(src);
		
		var filtered = src;
		filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
		filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
		filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
		
		if (/^[\],:{}\s]*$/.test(filtered))
			return eval("(" + src + ")");
		else
			throw new SyntaxError("Error parsing JSON, source is not valid.");
	};

	/** jQuery.quoteString(string)
		Returns a string-repr of a string, escaping quotes intelligently.  
		Mostly a support function for toJSON.
	
		Examples:
			>>> jQuery.quoteString("apple")
			"apple"
		
			>>> jQuery.quoteString('"Where are we going?", she asked.')
			"\"Where are we going?\", she asked."
	 **/
	$.quoteString = function(string)
	{
		if (string.match(_escapeable))
		{
			return '"' + string.replace(_escapeable, function (a) 
			{
				var c = _meta[a];
				if (typeof c === 'string') return c;
				c = a.charCodeAt();
				return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
			}) + '"';
		}
		return '"' + string + '"';
	};
	
	var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
	
	var _meta = {
		'\b': '\\b',
		'\t': '\\t',
		'\n': '\\n',
		'\f': '\\f',
		'\r': '\\r',
		'"' : '\\"',
		'\\': '\\\\'
	};
})(jQuery);

/**
 * jQuery Mousewheel 3.1.13
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 */

(function (factory) {
	if ( typeof define === 'function' && define.amd ) {
		// AMD. Register as an anonymous module.
		define(['jquery'], factory);
	} else if (typeof exports === 'object') {
		// Node/CommonJS style for Browserify
		module.exports = factory;
	} else {
		// Browser globals
		factory(jQuery);
	}
}(function ($) {
	var toFix  = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
		toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
			['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
		slice  = Array.prototype.slice,
		nullLowestDeltaTimeout, lowestDelta;

	if ( $.event.fixHooks ) {
		for ( var i = toFix.length; i; ) {
			$.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
		}
	}

	var special = $.event.special.mousewheel = {
		version: '3.1.12',

		setup: function() {
			if ( this.addEventListener ) {
				for ( var i = toBind.length; i; ) {
					this.addEventListener( toBind[--i], handler, false );
				}
			} else {
				this.onmousewheel = handler;
			}
			// Store the line height and page height for this particular element
			$.data(this, 'mousewheel-line-height', special.getLineHeight(this));
			$.data(this, 'mousewheel-page-height', special.getPageHeight(this));
		},

		teardown: function() {
			if ( this.removeEventListener ) {
				for ( var i = toBind.length; i; ) {
					this.removeEventListener( toBind[--i], handler, false );
				}
			} else {
				this.onmousewheel = null;
			}
			// Clean up the data we added to the element
			$.removeData(this, 'mousewheel-line-height');
			$.removeData(this, 'mousewheel-page-height');
		},

		getLineHeight: function(elem) {
			var $elem = $(elem),
				$parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
			if (!$parent.length) {
				$parent = $('body');
			}
			return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
		},

		getPageHeight: function(elem) {
			return $(elem).height();
		},

		settings: {
			adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
			normalizeOffset: true  // calls getBoundingClientRect for each event
		}
	};

	$.fn.extend({
		mousewheel: function(fn) {
			return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
		},

		unmousewheel: function(fn) {
			return this.unbind('mousewheel', fn);
		}
	});


	function handler(event) {
		var orgEvent   = event || window.event,
			args	   = slice.call(arguments, 1),
			delta	  = 0,
			deltaX	 = 0,
			deltaY	 = 0,
			absDelta   = 0,
			offsetX	= 0,
			offsetY	= 0;
		event = $.event.fix(orgEvent);
		event.type = 'mousewheel';

		// Old school scrollwheel delta
		if ( 'detail'	  in orgEvent ) { deltaY = orgEvent.detail * -1;	  }
		if ( 'wheelDelta'  in orgEvent ) { deltaY = orgEvent.wheelDelta;	   }
		if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY;	  }
		if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }

		// Firefox < 17 horizontal scrolling related to DOMMouseScroll event
		if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
			deltaX = deltaY * -1;
			deltaY = 0;
		}

		// Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
		delta = deltaY === 0 ? deltaX : deltaY;

		// New school wheel delta (wheel event)
		if ( 'deltaY' in orgEvent ) {
			deltaY = orgEvent.deltaY * -1;
			delta  = deltaY;
		}
		if ( 'deltaX' in orgEvent ) {
			deltaX = orgEvent.deltaX;
			if ( deltaY === 0 ) { delta  = deltaX * -1; }
		}

		// No change actually happened, no reason to go any further
		if ( deltaY === 0 && deltaX === 0 ) { return; }

		// Need to convert lines and pages to pixels if we aren't already in pixels
		// There are three delta modes:
		//   * deltaMode 0 is by pixels, nothing to do
		//   * deltaMode 1 is by lines
		//   * deltaMode 2 is by pages
		if ( orgEvent.deltaMode === 1 ) {
			var lineHeight = $.data(this, 'mousewheel-line-height');
			delta  *= lineHeight;
			deltaY *= lineHeight;
			deltaX *= lineHeight;
		} else if ( orgEvent.deltaMode === 2 ) {
			var pageHeight = $.data(this, 'mousewheel-page-height');
			delta  *= pageHeight;
			deltaY *= pageHeight;
			deltaX *= pageHeight;
		}

		// Store lowest absolute delta to normalize the delta values
		absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );

		if ( !lowestDelta || absDelta < lowestDelta ) {
			lowestDelta = absDelta;

			// Adjust older deltas if necessary
			if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
				lowestDelta /= 40;
			}
		}

		// Adjust older deltas if necessary
		if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
			// Divide all the things by 40!
			delta  /= 40;
			deltaX /= 40;
			deltaY /= 40;
		}

		// Get a whole, normalized value for the deltas
		delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
		deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
		deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);

		// Normalise offsetX and offsetY properties
		if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
			var boundingRect = this.getBoundingClientRect();
			offsetX = event.clientX - boundingRect.left;
			offsetY = event.clientY - boundingRect.top;
		}

		// Add information to the event object
		event.deltaX = deltaX;
		event.deltaY = deltaY;
		event.deltaFactor = lowestDelta;
		event.offsetX = offsetX;
		event.offsetY = offsetY;
		// Go ahead and set deltaMode to 0 since we converted to pixels
		// Although this is a little odd since we overwrite the deltaX/Y
		// properties with normalized deltas.
		event.deltaMode = 0;

		// Add event and delta to the front of the arguments
		args.unshift(event, delta, deltaX, deltaY);

		// Clearout lowestDelta after sometime to better
		// handle multiple device types that give different
		// a different lowestDelta
		// Ex: trackpad = 3 and mouse wheel = 120
		if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
		nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);

		return ($.event.dispatch || $.event.handle).apply(this, args);
	}

	function nullLowestDelta() {
		lowestDelta = null;
	}

	function shouldAdjustOldDeltas(orgEvent, absDelta) {
		// If this is an older event and the delta is divisable by 120,
		// then we are assuming that the browser is treating this as an
		// older mouse wheel event and that we should divide the deltas
		// by 40 to try and get a more usable deltaFactor.
		// Side note, this actually impacts the reported scroll distance
		// in older browsers and can cause scrolling to be slower than native.
		// Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
		return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
	}

}));

/**
 * My Extensions for jQuery
 */
(function($) {
	/**
	 example
	 $.cookie('name', 'value');
	 $.cookie('name', 'value', {expires: 7, path: '/', domain: 'jquery.com', secure: true});
	 $.cookie('name', null);
	 */
	$.cookie = function(name, value, options) {
		if (typeof value != 'undefined') { // name and value given, set cookie
			options = options || {};
			if (value === null) {
				value = '';
				options.expires = -1;
			}
			var expires = '';
			if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
				var date;
				if (typeof options.expires == 'number') {
					date = new Date();
					date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
				} else {
					date = options.expires;
				}
				expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
			}
			// CAUTION: Needed to parenthesize options.path and options.domain
			// in the following expressions, otherwise they evaluate to undefined
			// in the packed version for some reason...
			var path = options.path ? '; path=' + (options.path) : '';
			var domain = options.domain ? '; domain=' + (options.domain) : '';
			var secure = options.secure ? '; secure' : '';
			document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
		} else { // only name given, get cookie
			var cookieValue = null;
			if (document.cookie && document.cookie != '') {
				var cookies = document.cookie.split(';');
				for (var i = 0; i < cookies.length; i++) {
					var cookie = jQuery.trim(cookies[i]);
					// Does this cookie string begin with the name we want?
					if (cookie.substring(0, name.length + 1) == (name + '=')) {
						cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
						break;
					}
				}
			}
			return cookieValue;
		}
	};
	//load JS in batch
	$.setJS = function(list, in_turn=true, callback, process) {
		let num_total = list.length;
		let num_done = 0
		let loader = function(script) {
			return new Promise((resolve, reject) => {
				$.getScript(script, function(data, textStatus){
					if(textStatus==='success') {
						resolve(data);
					} else {
						reject(textStatus);
					}
				});
			});
		};
		if(in_turn) {
			let p = loader(list[0]);
			for(let i=1,m=list.length;i<m;i++) {
				p = p.then(()=>{
					num_done++;
					if(typeof(process)==='function') process(num_done, num_total, list[i-1]);
					return loader(list[i]);
				}).catch((e)=>{
					console.log(e)
				});
			}
			p.then(()=>{
				num_done++;
				if(typeof(process)==='function') process(num_done, num_total, list[num_done-1]);
				if(typeof(callback)==='function') callback();
			});
		} else {
			let result = [];
			list.forEach(current => {
					let p = loader(current).then(()=>{
						num_done++;
						if(typeof(process)==='function') process(num_done, num_total, current);
					});
					result.push(p);
				}
			);
			Promise.all(result).then(()=>{
				if(typeof(callback)==='function') callback();
			}).catch((e)=>{
				console.log(e)
			});
		}
	}
	//load CSS in batch
	$.setCSS = function(css) {
		if(css==null) return;
		if(css instanceof Array) {
			for(var i=0,m=css.length;i<m;i++) {
				jQuery.setCSS(css[i]);
			}
		} else {
			var name = md5(css);
			$("head").append($('<link id="css_'+name+'" rel="stylesheet" href="'+css+'" type="text/css" media="screen" />'));
			setTimeout(function(){
				$("#css_"+name).attr("href", css);
			}, 1000);
		}
	};
	//load Vendor's Code
	$.vendor = function(name, option) {
		option = $.extend({
			'add_css' : false,
			'name_fix' : '',
			'callback' : function () {}
		}, option);
		if(option.add_css===true) option.add_css = '';
		if(option.name_fix===true) option.name_fix = '.min';
		if(option.name_fix===false) option.name_fix = '';
		let root = typeof(global.root)==='undefined'?'/':global.root;
		$.getScript(root+'vendor/'+name+'/'+name+option.name_fix+'.js', () => {
			if(option.add_css!==false) {
				$.setCSS(root+"vendor/"+name+"/"+name+option.add_css+".css");
			}
			option.callback();
		});
	};
	//serialize form data for the use of json
	$.fn.serializeObject = function() {
		var o = {};
		var a = this.serializeArray();
		$.each(a, function() {
			if (o[this.name]) {
				if (!o[this.name].push) {
					o[this.name] = [ o[this.name] ];
				}
				o[this.name].push(this.value || '');
			} else {
				o[this.name] = this.value || '';
			}
		});
		return o;
	};
	//outerHTML
	$.fn.outerHTML = function(s) {
		return (s) ? this.before(s).remove() : $('<p>').append(this.eq(0).clone()).html();
	};
	//cssText
	$.fn.cssText = function(css) {
		var css_list = css.trim().split(";");
		var cur_style = null;
		for(var i=0,m=css_list.length;i<m;i++) {
			css_list[i] = css_list[i].trim();
			if(css_list[i].length<3) continue;
			cur_style = css_list[i].split(":");
			if(cur_style.length==2) $(this).css(cur_style[0].trim(), cur_style[1].trim());
		}
		return this;
	};
	//disableSelection
	$.fn.disableSelection = function() {
		return this.attr('unselectable', 'on')
			.css({'-moz-user-select':'-moz-none',
				'-o-user-select':'none',
				'-khtml-user-select':'none',
				'-webkit-user-select':'none',
				'-ms-user-select':'none',
				'user-select':'none'})
			.bind('selectstart', false);
	};
})(jQuery);